package cn.edu.lcu.cs.javaprogramming.oop.innerclass;


import cn.edu.lcu.cs.javaprogramming.util.Showable;

/**
 * 内部类演示，内部类实现了一个接口
 * 
 * @author Ling
 *
 */
public class InnerClazzImplementsInterface {
	public static void main(String[] args) {
//		anonymousInnerClazz();
//		namedInnerClazz();
		lambdaInnerClazz();
	}

	/**
	 * <li>具名内部类演示</li>
	 */
	private static void namedInnerClazz() {
		/**
		 * 带名称的内部类，在定义之外可以访问
		 * 
		 * @author Ling
		 *
		 */
		class NamedInnerClazz implements Showable {
			@Override
			public void show() {
				System.out.println("NamedInnerClazz");
			}
		}

		// 因为是带名称的内部类，可以通过类名访问
		NamedInnerClazz innerClazz = new NamedInnerClazz();
		innerClazz.show();

		// 可以重复通过类名访问具名内部类
		NamedInnerClazz innerClazz2 = new NamedInnerClazz();
		innerClazz2.show();

		// 两个不同的内部类实例
		// false
		System.out.println(innerClazz == innerClazz2);

	}

	/**
	 * <li>匿名内部类演示</li>
	 * <li>因为是匿名的，它没有名字，没法在别处访问这个类</li>
	 * <li>因为是匿名的，创建之后需要立即使用它生成实例</li>
	 * <li>匿名内部类的代码一般都非常独特，仅在定义的地方使用，在其它地方没有使用的意义</li>
	 * <li>因为这个内部类实现了Showable接口，可以用Showable类型的变量进行访问</li>
	 */
	private static void anonymousInnerClazz() {
		// 创建了一个匿名内部类，此类实现了Showable接口
		// 在创建内部类之后立即生成了一个实例，可以赋值给一个接口类型的变量
		Showable showable = new Showable() {
			@Override
			public void show() {
				System.out.println("anonymousInnerClazz");
			}
		};
		// 调用内部类的方法
		showable.show();
	}

	/**
	 * <li>匿名内部类演示，用Lambda表达式实现</li>
	 * <li>因为是匿名的，它没有名字，没法在别处访问这个类</li>
	 * <li>因为是匿名的，创建之后需要立即使用它生成实例</li>
	 * <li>匿名内部类的代码一般都非常独特，仅在定义的地方使用，在其它地方没有使用的意义</li>
	 */
	private static void lambdaInnerClazz() {
		/**
		 * 用lambda表达式实现匿名内部类
		 * 通过变量的类型Showable，编译器推断出后边的Lambda表达式要实现这个接口
		 * 在这个接口中仅有一个抽象方法，于是Lambda表达式实现了这个唯一的方法show()
		 * 后续就可以访问show()方法了 
		 */
		Showable showable = ()->System.out.println("lambdaInnerClazz");
		showable.show();
	}
}